package org.zhangkun.jmsg.core.network.filetransport;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.Socket;

import org.zhangkun.jmsg.bean.DataPackage;
import org.zhangkun.jmsg.bean.DataUnPack;
import org.zhangkun.jmsg.core.listener.AcceptFileRequestListener;
import org.zhangkun.jmsg.core.listener.CancelFileTransportListener;
import org.zhangkun.jmsg.core.network.NetConnection;
import org.zhangkun.jmsg.core.network.exception.DataPackageParseException;
import org.zhangkun.jmsg.ui.swing.FileTransportViewDialog;
import org.zhangkun.jmsg.util.FileUtil;
import org.zhangkun.jmsg.util.GlobalVar;

public class SendFiles extends FileTransport implements
		AcceptFileRequestListener, CancelFileTransportListener, Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1691619197253540972L;

	/**
	 * 将整形数dec转化为固定长度（8位）的十六进制字符串
	 * 
	 * @param dec
	 * @return
	 */
	public static String dec2Hex(int dec) {
		StringBuffer sb = new StringBuffer();

		for (int i = 0; i < 8; i++) {
			int tmp = (dec >> (7 - i % 8) * 4) & 0x0f;
			if (tmp < 10)
				sb.append(tmp);
			else
				sb.append((char) ('A' + (tmp - 10)));
		}
		return sb.toString();
	}

	public static FileMsgPackage parseRequest(Socket socket)
			throws DataPackageParseException {
		// TODO Auto-generated method stub
		try {
			InputStream is = socket.getInputStream();
			FileMsgPackage fmp = new FileMsgPackage();
			DataUnPack dup = new DataUnPack();
			byte[] buffer = new byte[BUFFER_SIZE];
			int length = is.read(buffer);
			String msg = new String(buffer, 0, length,
					GlobalVar.TRANSPORT_ENCODING);
			dup.unPack(msg);
			fmp.unpackToRequestMsg(dup.getMsg());
			fmp.setDataType(dup.getDataType());
			return fmp;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			return null;
		}
	}

	private FileMsgPackage fmp;

	private String packageID;

	public SendFiles() {
		// TODO Auto-generated constructor stub
		super(null, SEND);
	}

	@Override
	public boolean acceptFileRequest(Socket socket, FileMsgPackage fmp) {
		// TODO Auto-generated method stub
		// System.out.println(packageID + " = " + fmp.getPackageID());
		if (fmp.getPackageID().equals(packageID)) {
			this.socket = socket;
			this.fmp = fmp;
			new Thread(this).start();
			return true;
		}
		return false;
	}

	public FileMsgPackage appendPath(String path, long allSize) {
		// TODO Auto-generated method stub
		File f = new File(path);
		FileMsgPackage fmp = new FileMsgPackage();
		fmp.setPath(path);
		fmp.setFileName(f.getName());
		fmp.setFileSize(allSize);
		fmp.setFileID(fmps.size());
		fmp.setFileMsgType((int) (f.isDirectory() ? DataPackage.IPMSG_FILE_DIR
				: DataPackage.IPMSG_FILE_REGULAR));
		fmp.setFileMktime(f.lastModified());
		fmps.add(fmp);
		return fmp;
	}

	@Override
	public boolean cancelFileTransportListener(String packageID) {
		// TODO Auto-generated method stub
		if (this.getPackageID().equals(packageID)) {
			this.status = STATUS_BY_STOP;
			return true;
		}
		return false;
	}

	public String getMsg() {
		// TODO Auto-generated method stub
		String ret = "" + (char) 0;
		for (int i = 0; i < fmps.size(); i++) {
			ret += fmps.get(i).packToResponse() + (char) 07;
		}
		return ret;
	}

	public String getPackageID() {
		// TODO Auto-generated method stub
		return packageID;
	}

	// private void send

	public void run() {
		System.out.println("收到文件请求：ID:" + fmp.getFileID());
		try {
			status = STATUS_RUNNING;
			int id = fmp.getFileID();
			if (id < 0 || id > fmps.size() - 1) {
				setError("请求的文件ID不存在！");
				status = STATUS_ERROR;
				return;
			}
			System.out.println(" 文件：" + fmps.get(fmp.getFileID()).getPath());
			index = id;
			currentTransportReadSize = 0;
			currentTransportSize = fmps.get(id).getFileSize();
			switch ((int) fmp.getDataType()) {
			case (int) DataPackage.IPMSG_GETFILEDATA:
				if (FileUtil.isFile(fmps.get(id).getPath())) {
					if (!sendFile()) {
						status = STATUS_ERROR;
						return;
					}
				} else {
					setError("请求的文件类型不符！" + fmp.getDataType());
					status = STATUS_ERROR;
					return;
				}
				break;
			case (int) DataPackage.IPMSG_GETDIRFILES:
				if (FileUtil.isDir(fmps.get(id).getPath())) {
					if (!sendFolder()) {
						status = STATUS_ERROR;
						return;
					}
				} else {
					setError("请求的文件夹类型不符！路径：" + fmps.get(id).getPath() + " 类型："
							+ fmp.getDataType());
					status = STATUS_ERROR;
					return;
				}
				break;
			default:
				setError("未知请求！");
				status = STATUS_ERROR;
				return;
			}
		} finally {
			if (status == STATUS_RUNNING) {
				status = STATUS_FINISH;
				// frm.getNetConnection().getAcceptFileRequestThread()
				// .removeListener(this);
			}
			if (socket != null)
				try {
					socket.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
	}

	private boolean sendFile() {
		// TODO Auto-generated method stub
		try {
			return sendFile(new File(fmps.get(fmp.getFileID()).getPath()));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			setError(e.getMessage());
			return false;
		}
	}

	private boolean sendFile(File file) throws IOException {
		System.out.println("sendFile " + file.getAbsolutePath() + " size "
				+ file.length());
		FileInputStream fis = null;
		currentFileName = file.getAbsolutePath();
		currentFileLength = file.length();
		currentFileReadLength = 0;
		int length = buffer.length;
		try {
			// System.out.println("sendFile send " + file.getAbsolutePath() +
			// " "
			// + buffer.length);
			fis = new FileInputStream(file);
			OutputStream os = socket.getOutputStream();
			while ((length = fis.read(buffer, 0, length)) != -1) {
				// System.out.println("已发送：" + currentReadLength);
				os.write(buffer, 0, length);
				os.flush();
				currentFileReadLength += length;
				allReadSize += length;
				currentTransportReadSize += length;
				length = buffer.length;
				// System.out.println("readLength " + length);
			}
			System.out.println("sendFile finish " + file.getAbsolutePath());
			return true;
		} finally {
			if (fis != null)
				try {
					fis.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			System.out.println("已发送：" + currentFileReadLength);

		}
	}

	private boolean sendFolder() {
		// TODO Auto-generated method stub
		try {
			sendSubfolder(new File(fmps.get(fmp.getFileID()).getPath()));
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			setError("发送失败！");
			return false;
		}
	}

	private void sendMsg(String name, long size, long type) throws IOException {
		String msg = ":" + name + ":" + Long.toHexString(size) + ":"
				+ Long.toHexString(type) + ":0:";
		// System.out.println(msg);
		OutputStream os = socket.getOutputStream();
		String str = (dec2Hex(msg.getBytes(GlobalVar.TRANSPORT_ENCODING).length + 8) + msg);
		System.out.println("sendMsg " + str);
		os.write(str.getBytes(GlobalVar.TRANSPORT_ENCODING));
		// os.flush();
	}

	private void sendSubfolder(File file) throws IOException {
		// TODO Auto-generated method stub
		System.out.println("进入目录： " + file.getAbsolutePath());
		sendMsg(file.getName(), 4096, DataPackage.IPMSG_FILE_DIR);
		File[] folder = file.listFiles();
		if (folder != null) {
			for (int i = 0; i < folder.length; i++)
				if (folder[i].isDirectory())
					sendSubfolder(folder[i]);
				else {
					sendMsg(folder[i].getName(), folder[i].length(),
							DataPackage.IPMSG_FILE_REGULAR);
					sendFile(folder[i]);
				}
		}
		System.out.println("离开目录： " + file.getAbsolutePath());
		sendMsg(file.getName(), 4096, DataPackage.IPMSG_FILE_RETPARENT);
	}

	public void setPackageID(String packageID2) {
		// TODO Auto-generated method stub
		this.packageID = packageID2;
	}

	public void startUp() {
		// TODO Auto-generated method stub
		FileTransportViewDialog.addFileTransport(this);
		NetConnection.instance.getAcceptFileRequestThread().addListener(this);
		NetConnection.instance.getResponseDataPackage()
				.addCancelFileTransportListener(this);
		status = STATUS_WAITFORSTART;
		allReadSize = 0;
		allSize = 0;
		for (int i = 0; i < fmps.size(); i++) {
			if (fmps.get(i).getFileSize() == 0) {
				allSize = 0;
				break;
			}
			allSize = fmps.get(i).getFileSize();
		}
	}
}